import * as Cesium from 'cesium'
import gcoord from 'gcoord'
import BaiduWebMercatorProjection from './BaiduWebMercatorProjection'
/**
 * 百度墨卡托投影瓦片方案类
 * 百度地图使用的投影方式，与Web Mercator投影不同，百度地图的投影中心在百度地图的中心位置，而不是WGS84的中心位置。
 * @class BaiduMercatorTilingScheme
 * @extends Cesium.WebMercatorTilingScheme
 * @example
 * // 创建百度墨卡托投影瓦片方案
 * const tilingScheme = new BaiduMercatorTilingScheme({
 *   resolutions: [256 * Math.pow(2, 18 - i) for i in 0..18],
 *   rectangleSouthwestInMeters: new Cesium.Cartesian2(-20037726.37, -12474104.17),
 *   rectangleNortheastInMeters: new Cesium.Cartesian2(20037726.37, 12474104.17)
 * });
/**
 * @classdesc 百度墨卡托投影瓦片方案类
 */
class BaiduMercatorTilingScheme extends Cesium.WebMercatorTilingScheme {
    /**
     * 各层级的分辨率数组
     * @type {Array<number>}
     */
    resolutions
    
    /**
     * 构造函数
     * @param {Object} options - 配置参数对象
     * @param {Array<number>} options.resolutions - 各层级分辨率数组
     * @param {Cesium.Cartesian2} options.rectangleSouthwestInMeters - 西南角坐标（米）
     * @param {Cesium.Cartesian2} options.rectangleNortheastInMeters - 东北角坐标（米）
     */
    constructor(options) {
        super(options)
        this.resolutions = options.resolutions||[]
        let projection = new BaiduWebMercatorProjection()
        this.projection.project = function (cartographic, result) {
            result = result || {}
            result = gcoord.transform([
                Cesium.Math.toDegrees(cartographic.longitude),
                Cesium.Math.toDegrees(cartographic.latitude)
            ], gcoord.WGS84, gcoord.BD09);
            result[0] = Math.min(result[0], 180)
            result[0] = Math.max(result[0], -180)
            result[1] = Math.min(result[1], 74.000022)
            result[1] = Math.max(result[1], -71.988531)
            result = projection.lngLatToPoint({
                lng: result[0],
                lat: result[1],
            })
            return new Cesium.Cartesian3(result.x, result.y)
        }
        this.projection.unproject = function (cartesian, result) {
            result = result || {}
            result = projection.mercatorToLngLat({
                lng: cartesian.x,
                lat: cartesian.y,
            })
            result = gcoord.transform([
                result.lng,
                result.lat
            ], gcoord.BD09, gcoord.WGS84);
            return new Cesium.Cartographic(
                Cesium.Math.toRadians(result[0]),
                Cesium.Math.toRadians(result[1])
            )
        }
    }

    /**
     * 将瓦片坐标转换为原生矩形范围
     * @param {number} x - 瓦片X坐标
     * @param {number} y - 瓦片Y坐标
     * @param {number} level - 缩放级别
     * @param {Cesium.Rectangle} [result] - 可选的结果对象
     * @returns {Cesium.Rectangle} 矩形范围
     */
    tileXYToNativeRectangle(x, y, level, result) {
        const tileWidth = this.resolutions[level]
        const west = x * tileWidth
        const east = (x + 1) * tileWidth
        const north = ((y = -y) + 1) * tileWidth
        const south = y * tileWidth

        if (!Cesium.defined(result)) {
            return new Cesium.Rectangle(west, south, east, north)
        }

        result.west = west
        result.south = south
        result.east = east
        result.north = north
        return result
    }

    /**
     * 将位置转换为瓦片坐标
     * @param {Cesium.Cartographic} position - 地理坐标位置
     * @param {number} level - 缩放级别
     * @param {Cesium.Cartesian2} [result] - 可选的结果对象
     * @returns {Cesium.Cartesian2|undefined} 瓦片坐标，若位置不在范围内则返回undefined
     */
    positionToTileXY(position, level, result) {
        const rectangle = this.rectangle
        if (!Cesium.Rectangle.contains(rectangle, position)) {
            return undefined
        }
        const projection = this.projection
        const webMercatorPosition = projection.project(position)
        if (!Cesium.defined(webMercatorPosition)) {
            return undefined
        }
        const tileWidth = this.resolutions[level]
        const xTileCoordinate = Math.floor(webMercatorPosition.x / tileWidth)
        const yTileCoordinate = -Math.floor(webMercatorPosition.y / tileWidth)
        if (!Cesium.defined(result)) {
            return new Cesium.Cartesian2(xTileCoordinate, yTileCoordinate)
        }
        result.x = xTileCoordinate
        result.y = yTileCoordinate
        return result
    }
}
export default BaiduMercatorTilingScheme